import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

/* 创建一个 WebSocket 连接。 消息列表组件，聊天组件需要 */

// 引入 声明常量，存放的文件
// import { USER_LOGIN} from '@/store/modules/mutations-types';
/* ---------- 引入 websocket 地址------------ */
import $C from '@/common/conflig.js';
/* ---------- http封装的请求方法 ------------ */
import $http from '@/common/request.js';
/* ---------- 引入工具 util.js 使用排序方法置顶------------ */
import $U from '@/common/util.js'

export default new Vuex.Store({
	state:{
		// 登录状态，默认false,未登录
		loginStatus:false,
		token:false, // 读取 user中的token
		// 用户所有信息
		user:{
			// "id": 7,
			// "username": "zcmcss",
			// "userpic": "https://tangzhe123-com.oss-cn-shenzhen.aliyuncs.com/Appstatic/qsbk/demo/userpic/1.jpg",
			// "password": true,
			// "phone": "13450772004",
			// "email": "123@qq.com",
			// "status": 1,
			// "create_time": null,
			// "logintype": "username",
			// "token": "a8bb3f6f50ff5049d70b6022b48e1f45c24a96f8",
			// "userinfo": {
			// 	"id": 1,
			// 	"user_id": 7,
			// 	"age": 23,
			// 	"sex": 1,
			// 	"qg": 1,
			// 	"job": "IT",
			// 	"path": "北京市-市辖区-朝阳区",
			// 	"birthday": "1996-06-12"
			// },
			// user_bind:{
			// 	"qq": {
			// 		"id": 229,
			// 		"nickname": "airson"
			// 	}
			// }
		},
		/* 判断 第三方登录，是否绑定了账号
		  user_bind:{
			  "qq": {
			      "id": 931,
			      "nickname": "帐号已注销"
			  }
		} */
		// 1. scoket 连接状态
		IsOpen:false,
		/* 2. ScoketTask 连接成功会返回一个对象
		 https://uniapp.dcloud.net.cn/api/request/socket-task.html 
		 使用 SocketTask 创建多个，WebSocket之会创建一个连接*/
		SocketTask:false,
		// 3. 是否上线（会员id绑定客户端id，验证用户身份，通过则绑定）
		IsOnline:false, 
		// 4. 当前聊天对象（进入聊天页面获取）
		ToUser:{
			// 通过判断user_id是否为0，当前用户处于什么场景下
			user_id:0, 
			username:"", // 用户名称
			userpic:"" // 用户头像
		},
		// 聊天会话列表
		chatList:[]
	},
	// 类似 computed计算属性
	getters:{
	 // 4.6 处理计算  总未读数
	 totalNoread(state) {
	   	 let total = 0
	   	  // 循环 聊天列表
		  state.chatList.forEach(item => {
		  	 total += item.noread // 总数 = 每个聊天列表数量（相加）
		  })
	   	  return total // 返回总数
	   }
	},
	mutations:{
		// 5.8 创建聊天对象
		createToUser(state, ToUser) {
		    state.ToUser = ToUser
		},
		// 5.9 关闭聊天对象
		closeToUser(state) {
		  state.ToUser = {
			user_id: 0,
			username: "",
			userpic: ""
		  }
		},
		// 登录
		login(state, user) {
			// 修改登录状态
			state.loginStatus = true
			// 获取用户信息，赋值 到 state中
			state.user = user
			state.token =state.user.token
			// 将获取到的 用户信息，存入本地存储当中
			uni.setStorageSync('user', JSON.stringify(user))
			// 通知 首页，刷新页面
			uni.$emit('updateIndex')
		},
		// 退出登录
		logout(state) {
			state.user = {} // 清除 state中的用户 信息
			state.loginStatus = false // 修改登录状态
			state.token = false
			// 清除本地存储的 用户信息
			uni.removeStorageSync('user')
			// 通知 首页，刷新页面
			uni.$emit('updateIndex')
		},
		// 修改用户信息 {手机号/邮箱/密码key，修改的信息value}
		editUserInfo(state,{key,value}){
			// 根据key 修改 value
			state.user[key] = value
			// 重新添加 用户信息，存入本地存储当中
			uni.setStorageSync('user', JSON.stringify(state.user))
		},
		// 修改资料 
		editUserMessage(state,obj){
		  // 如果用户存在，再去修改
		  if(state.user.userinfo){
		  	state.user.userinfo.sex=obj.sex
		  	state.user.userinfo.qg=obj.qg
		  	state.user.userinfo.job=obj.job
		  	state.user.userinfo.path=obj.path
		  	state.user.userinfo.birthday=obj.birthday
		  	uni.setStorageSync('user', JSON.stringify(state.user))
		  }
		},
		// 4.3 储存会话列表 到本地存储当中
		saveChatList(state,list){
			// ('需要存储的字段'+用户id+将接收到的列表数据，序列化为字符串)
			uni.setStorageSync('chatlist_' + state.user.id, JSON.stringify(list))
		},
		// (最后)删除会话列表
		clearChatList(state,list){
			uni.removeStorageSync('chatlist_'+state.user.id)
			state.chatList = []
		},
		// 5.3 储存与某个用户聊天内容列表
		saveChatDetail(state, { list, toId }) {
			// 拿到自己的id
			let myId = state.user.id
			// 判断 如果 聊天对象id存在。返回toId 否则 当前会话对象id
			toId = toId ? toId : state.ToUser.user_id
			// chatdetail_[当前用户id]_[聊天对象id]
			let key = 'chatdetail_' + myId + '_' + toId
			// 存入本地存储，('chatlist_字段',序列化 聊天内容列表)
			uni.setStorageSync(key, JSON.stringify(list))
		}
	},
	/* 类似组件中的 methods ，actions是异步的，可以认为是一个动作-------------------
	   如果要调用mutations方法需要; 解构{{state，commit}} 
	   如果要调用acitons方法需要; 解构{{state，dispatch}} 
	*/
	actions:{
		// 6. 关闭socket
		closeSocket({ state }) {
			// 判断scoket 连接状态，如果处于打开状态
		    if(state.IsOpen){ // 关闭socket
				state.SocketTask.close()
			}	
		},
		// 初始化登录状态
		initLoginUser({state,dispatch}) {
			let user = uni.getStorageSync('user') // 从本地存储获取用户信息
			if (user) {
				// 转化用户信息，进入app时读取
				state.user = JSON.parse(user) 
				// 修改登录状态
				state.loginStatus = true
				state.token =state.user.token
				// 打开socket
			    dispatch('openSocket')
			}
		},
		// 1. 打开socket
		openSocket({state,dispatch}){
			// 防止重复连接
			if(state.IsOpen) return
			// 连接 ScoketTask(uni.connectSocket创建一个WebSocket连接)
			state.SocketTask = uni.connectSocket({
				url:$C.websocketUrl, // 需要连接的地址
				// 接口调用结束的回调函数，成功失败都会执行
				complete: () => {}
			});
			// 如果 未连接 SocketTask 直接终止
			if (!state.SocketTask) return;
			// 监听开启
			state.SocketTask.onOpen(() => {
				console.log('将连接状态设为已连接');
				// 将连接状态 改为 true
				state.IsOpen=true;
			});
			// 监听关闭
			state.SocketTask.onClose(()=>{
				console.log('连接关闭');
				// 将连接状态 改为 false
				state.IsOpen=false;
				// 断开 SocketTask 连接
				state.SocketTask =false
				state.IsOnline = false
				// 清空会话列表
				// 更新未读数提示
			});
			// 监听错误
			state.SocketTask.onError(()=>{
				console.log('连接错误');
				state.IsOpen=false;
				state.SocketTask =false;
				state.IsOnline = false
			});
			// 监听接收信息
			state.SocketTask.onMessage((e)=>{
			   console.log('接收消息',e); // 接收到的值如下，需要转换
			   // data:"{"type":"bind","data":"7f0000010b56000001f3"}"
			   // 字符串转json
			   let res = JSON.parse(e.data)
			   // 绑定返回结果
			   if(res.type == 'bind'){
			      /* 用户绑定 res.data就是上面 接收的data
				    7f0000010b56000001f3 = res.data(客户端id)
				  */
			      return dispatch('userBind', res.data)
			   }
			   // 判断接收发送的 类型
			   if (res.type !== 'text') return;
			   /*
			   {
				   to_id:1, //接收人
				   from_id:12, // 发送人id
				   from_username:'某某', // 发送人昵称
				   from_userpic:"用户头像",
				   type:'text', // 发送类型
				   data:'你好啊', // 发送内容
				   time:151235451 // 接收到的时间
			   }
			   */
			   // 调用 处理接收消息 异步事件
			   dispatch('handleChatMessage', res)
			})
		},
		// 2. 用户绑定 (client_id客户端id)
		userBind({ state, dispatch }, client_id) {
			$http.post('/chat/bind',{
				type:"bind" ,// 类型根据 接口文档来传入
				client_id: client_id// 客户端id
			},{
				token:true,
			}).then(data=>{
				/* 绑定成功，返回的数据
				  { "type":"bind",
				    "status":true}
				 */ 
				console.log('绑定成功',data);
				// 开始上线
				if (data.status && data.type === 'bind') {
					// 将上线状态 改为 true，上线状态
					state.IsOnline=true;
					// 5.4 初始化会话列表
					dispatch('initChatList')
					// 5.6 获取未读信息
					dispatch('getUnreadMessages')
				}
			}).catch(err=>{
				// 失败 退出登录。重新连接等处理
			})
		},
		// 5.7 获取未读信息
		getUnreadMessages({ state, dispatch }) {
		   console.log('获取未读信息中...');
			   $http.post('/chat/get',{},{
				   token:true,
			   }).then((data)=>{
				   console.log('获取未读信息成功',data);
				   data.forEach(msg=>{
					   // 处理接收消息
					   dispatch('handleChatMessage', msg)
				 })
			})
		},
		// 5.5 初始化会话列表
		async initChatList({ state, dispatch, commit }) {
			// 去本地存储获取所有 会话列表
		    state.chatList = await dispatch('getChatList')
			console.log('初始化会话列表',state.chatList);
			// 更新 tabbar底部导航角标
			dispatch('updateTabbarBadge')
		},
		// 3. 处理接收消息
	    handleChatMessage({ state, dispatch }, data) {
			console.log('处理接收消息',data);
			// 全局通知接口
			uni.$emit('UserChat',data);
			// 4.7 存储到 （chatdetail是与当前用户所有的聊天 记录） 
			dispatch('updateChatDetailToUser', {
				data,// 接收到的消息
				send: false// true为发送。false为接收
			})
			// 3.1 更新会话列表
			dispatch('updateChatList', data)
		},
		/* 3.2  更新聊天会话列表
		 (如果不使用async 这个事件 还会往下执行，这里使用async改为同步事件)
		 等待 await dispatch事件，执行完毕后，在往下执行
		 */
		async updateChatList({ state, dispatch, commit },data) {
			console.log('更新聊天会话列表',data);
			// 3.3 是否是本人发送 （data发送人 ===state自己）
			let isMysend = data.from_id === state.user.id
			// let isMySend = send
			console.log(isMysend?'本人发送的信息':'对方发送的信息');
			// 3.4 获取之前会话(获取到用户id)
			let chatList = await dispatch('getChatList')
			/* 3.6 判断是否已存在该会话，存在：将当前会话置顶，不存在，创建并追加至头部*/
			// 获取用户 根据id查找用户 索引值
			let i = chatList.findIndex((v) => {
				//  判断当前 用是否与 发送人。或接收人有关 
				return v.user_id == data.to_id || v.user_id == data.from_id;
			})
			//  3.7 当前会话不存在，创建会话
			if(i=== -1){
				// 3.8  接收到的消息转会话
				let obj = await dispatch('formatChatListObject',data)
				// 如果不是本人发送（那就是接收信息）
				if(!isMysend){
					obj.noread=1;
				}
				console.log('不存在当前会话，创建接收到的信息',obj);
				// 追加到消息列表 头部
				chatList.unshift(obj);
			}else{ 
				// 4. 会话存在,将当前会话置顶，修改chatList中当前会话的内容data和time时间显示
				let item = chatList[i]
				item.data=data.data //修改内容
				item.type=data.type //修改类型（文本，视频，图片)
				item.time=data.time //修改时间
				/* 4.1 判断是否在与 对方聊天，如果不是未读数+1，底部消息栏导航+1（排除本人发送消息）
			    (如果不是本人发送；并且 当前发送消息对象 不等于 当前会话的对象) */
				if (!isMysend && state.ToUser.user_id !== item.user_id) {
				  // 未读数++
				  item.noread++
				}
				console.log('存在当前会话',item);
				// 置顶当前会话 (聊天列表，根据id查找用户 索引值)
				chatList = $U._toFirst(chatList, i)
			}
			// 4.2 存储到本地存储 中
			state.chatList = chatList
			commit('saveChatList', chatList)
			/* 4.4 如果不处于聊天当中，更新未读数
			 当前发送消息对象 不等于 当前会话的对象; 并且 如果不是本人发送*/
			if (!isMysend && data.from_id !== state.ToUser.user_id) {
				// 更新数字角标，未读数
				await dispatch('updateTabbarBadge')
			}
		},
		/* 3.5 获取所有聊天会话列表 (这个方法是异步的，需要等待执行完，在往下执行)
		（需要return。返回当前用户的对象信息，调用这个方法，需要await）*/
		getChatList({state}){
			// 获取本地存储，('chatlist_字段'+当前用户)的本地存储
			let list = uni.getStorageSync('chatlist_' + state.user.id);
			// 如果当前用户存在，反序列化取出，否则为空数组
			return list ? JSON.parse(list) : []
		},
		/* 5. 获取与某个用户聊天内容列表 */
		getChatDetailToUser({ state }, toId = 0) {
			// 拿到自己的id
			let myId = state.user.id
			// 判断 如果 聊天对象id存在。返回toId 否则 当前会话对象id
			toId = toId ? toId : state.ToUser.user_id
			// chatdetail_[当前用户id]_[聊天对象id]
			let key = 'chatdetail_' + myId + '_' + toId
			// 获取本地存储，('chatlist_字段'+key)
			let list = uni.getStorageSync(key)
			// 如果当前用户存在，反序列化取出，否则为空数组
			return list ? JSON.parse(list) : []
		},
		
		// 3.9 消息转 聊天会话对象（转为聊天列表那样的格式）
		formatChatListObject({ state },data) {
			// 接收消息
			return {
				user_id:  data.from_id, // 用户ID
				avatar: data.from_userpic, // 用户头像
				username:data.from_username, // 用户名
				update_time:data.time ,// 最新消息时间戳
				data:data.data, // 内容
				noread:0 // 未读数
				// user_id: send ? state.ToUser.user_id : data.from_id,
				// avatar: send ? state.ToUser.avatar : data.from_userpic,
				// username: send ? state.ToUser.username : data.from_username,
				// update_time: data.time, // 最新消息时间戳
				// data: data.data,
				// noread: 0  // 未读数
			}
		},
		// 5. 消息转 对话对象（转为 聊天气泡，纯两人对聊格式）
		formatChatDetailObject({state},e){
			let data = e.data
			console.log('fromatChatDetailObject聊天气泡');
			console.log(e);
			// 如果 send为true(发送)，显示我自己的id头像名称 否则 发送人的...
			return {
				user_id: e.send ? state.user.id : data.from_id,
				avatar: e.send ? state.user.userpic : data.from_userpic,
				username: e.send ? state.user.username : data.from_username,
				data: data.data,// 内容
				type: data.type,// 类型（文本，视频，图片）
				create_time: new Date().getTime() // 接收消息时间戳
			}
		},
		// 4.5 更新未读数
		updateTabbarBadge({ state, getters }) {
			let total = getters.totalNoread
			console.log('更新未读数', total);
			// 未读数为0 ，移除
			if (total === 0) {
				console.log('移除未读数');
				return uni.removeTabBarBadge({
					index: 2// 底部导航。的索引，消息索引为2
				})
			}
			console.log('设置未读数',total);
			// 如果有未读数，设置数字角标
			uni.setTabBarBadge({
				index: 2,
				// 官方文档，数字角标需要 string类型，将总数转换为字符串
				text: total > 99 ? '99+' : total.toString()
			});
		},
		// 4.8 更新与某个用户聊天内容列表
		async updateChatDetailToUser({ state, dispatch, commit }, e) {
			console.log('更新与某个用户聊天内容列表',e)
		    // 拿到接收到的数据
			let data = e.data
			/* 如果 send为true,就说明这条消息发送出去了，那用户处于聊天气泡当中
			返回 当前会话的对象id 否则 当前发送消息对象id  */
			let toId = e.send ? state.ToUser.user_id : data.from_id
			//  4.9 获取与某个用户聊天内容的历史记录
		    let list = await dispatch('getChatDetailToUser', toId)
			//  5.1 最新接收到的消息。追加到 聊天历史记录当中
			list.push(await dispatch('formatChatDetailObject', e))
			//  5.2 储存到本地存储当中
			commit('saveChatDetail', {
				list, // 聊天历史记录
				toId // 聊天对象
			})
		},
		// 6.1 发送消息
		async sendChatMessage({ dispatch }, data) {
				/* {dispatch},data的格式
				 {
					 data:'发送内容',
					 type:'text'
				 }
				*/
				console.log('发送消息');
				// 6.2 组织发送消息格式
				let sendData = await dispatch('formatSendData', data)
				console.log('发送消息数据格式',sendData);
				/*
				{
					to_id:1, //接收人
					from_id:12, // 发送人id
					from_username:'某某', // 发送人昵称
					from_userpic:"用户头像",
					type:'text', // 发送类型
					data:'你好啊', // 发送内容
					time:151235451 // 接收到的时间
				}
				*/
			   // 6.4 更新与某个用户的消息历史记录
			  	dispatch('updateChatDetailToUser', {
			  	   data, // 组织发送消息格式
				   send:true // 发送，false为接收消息
			   })
			   // 6.5 更新 会话列表
			  dispatch('updateChatList',sendData)
			  return sendData
			},
			// 6.3 组织发送消息格式
			formatSendData({ state }, data) {
				return {
					to_id:state.ToUser.user_id, //发送消息人的id
					from_id:state.user.id, //登录用户id
					from_username:state.user.username, // 登录用户昵称
					from_userpic:state.user.userpic?state.user.userpic:'/static/default.jpg', //登录用户头像
					type:data.type, // 发送消息类型，（文本，音频，视频）
					data:data.data, // 内容
					time:new Date().getTime() //发送时间戳
				}
			},
			// 6.6 读取当前会话（去除未读数，更新tabbar)
			readChatMessage({ state, commit, dispatch }, item) {
				/*
				   user_id:331, // 用户ID
				   avatar:'/static/default.jpg', // 用户头像
				   username:'昵称', // 用户名
				   update_time:1578216988 ,// 最新消息时间戳
				   data:'看看有么有移除', // 内容
				   type:'text' // 类型(文本，视频。音频)
				   noread:0 // 未读数
				   time:'157822615177'
				*/
				console.log('读取当前会话（去除未读数,更新tabbar)',item);
				// 没有未读信息
				if (item.noread === 0) return;
				// 查询聊天列表，循环遍历，聊天列表
				state.chatList.forEach((v) => {
					// 判断当前点击的人id，和进入聊天气泡传入人的id是否全等
					if (v.user_id == item.user_id) {
						// 设置未读数为0
						v.noread =0
					}
				})
				// 储存
				commit('saveChatList', state.chatList)
				// 更新未读数
				dispatch('updateTabbarBadge')
			},
	}
})